home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / RTrace 1.0 / source / maclog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-18  |  22.9 KB  |  625 lines  |  [TEXT/KAHL]

  1. /*****************************************************************************\
  2. * maclog.c                                                                    *
  3. *                                                                             *
  4. * This file contains code which is specific to the Macintosh.  It contains    *
  5. * procedures which handle the log files and the log window.                   *
  6. \*****************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdarg.h>
  11. #include "rtresources.h"
  12.  
  13. /* externals */
  14. extern fpos_t    current_stdout_read_pos;/* position we're reading in stdout */
  15. extern fpos_t    current_stderr_read_pos;/* position we're reading in stderr */
  16. extern FILE        *stdout_file;            /* file to which stdout is redirected */
  17. extern FILE        *stderr_file;            /* file to which stderr is redirected */
  18. extern Rect        drag_window_rect;        /* the area in which windows may be dragged */
  19. extern MenuHandle windows_menu;            /* the Windows menu */
  20. extern int log_window_available;
  21.  
  22.  
  23. /* Globals */
  24. Rect            log_scroll_bar_rect;    /* Rectangle containing the scroll bar */
  25. Rect            log_text_rect;            /* Rectangle containing the log text */
  26. WindowPtr        log_window;                /* the log window */
  27. DialogRecord    log_window_rec;            /* storage for the log window */
  28. ControlHandle    vert_scroll_bar;        /* the vertical scroll bar in the log window */
  29. ControlHandle    horiz_scroll_bar;        /* the horizontal scroll bar in the log window */
  30. TEHandle        log_text;                /* a handle to the log TERec */
  31. Boolean            num_new_log_lines = 0;    /* number of lines to transfer to log window */
  32. short            window_height;            /* height of text in log window, in pixels */
  33. short            text_height;            /* height of log text, in pixels */
  34. char            last_log_line[200];        /* The last line in the log text */ 
  35.  
  36.  
  37. /* height of log window text line */
  38. #define LINE_HEIGHT            11
  39.  
  40. /* Maximum lines in the log window */
  41. #define    MAX_NUM_LOG_LINES    1000
  42.  
  43. /* Size of unzoomed log window */
  44. #define LOG_WINDOW_WIDTH    350
  45. #define LOG_WINDOW_HEIGHT    290
  46.  
  47. /* Prototypes */
  48. void add_line_to_log_window (char *line);
  49. void setup_log_text (void);
  50. void setup_log_window(void);
  51. void update_log_window (void);
  52. void update_scroll_bar(void);
  53. void handle_log_click(Point where);
  54. pascal void scroll_action_proc(ControlHandle control, short part);
  55. void handle_log_window_zoom(Point where, short part_code);
  56. void log_window_resized(void);
  57. void grow_log_window(Point where);
  58. void update_scroll_bar_with_active(Boolean active);
  59. void show_log_window(Boolean bring_to_front);
  60. void hide_log_window(void);
  61. void mac_write (FILE *file, ...);
  62. void process_mac_event(void);
  63.  
  64.  
  65.  
  66. /*****************************************************************************\
  67. * procedure setup_log_window                                                  *
  68. *                                                                             *
  69. * Purpose: This procedure sets up the log window.                             *
  70. *                                                                             *
  71. * Created by: Greg Ferrar                                                     *
  72. * Created on: August 29, 1992                                                 *
  73. * Modified:                                                                   *
  74. \*****************************************************************************/
  75.  
  76. void setup_log_window(void)
  77. {
  78.  
  79.     Rect        temp_rect = {0, 0, 0, 0};
  80.     WStateData    *wstate_data;
  81.     
  82.     /* Redirect stdout and stderr */
  83.  
  84.     stdout_file = freopen ("RTrace log file", "w+", stdout);
  85.     stderr_file = freopen ("RTrace error file", "w+", stderr);
  86.  
  87.     /* Remember our place in stdout_file and stderr_file */
  88.  
  89.     fgetpos(stdout_file, ¤t_stdout_read_pos);
  90.     fgetpos(stderr_file, ¤t_stderr_read_pos);
  91.  
  92.     /* Create the log window */
  93.     log_window = GetNewWindow(LOG_WINDOW, &log_window_rec, (WindowPtr) -1L);
  94.  
  95.     /* Clear out the WStateData so we will know later that this window has
  96.         not been placed */
  97.     BlockMove(&temp_rect, *(( (WindowPeek) log_window)->dataHandle), 8);
  98.  
  99.     /* Create a new TEHandle for the log text-- don't worry about the
  100.         rectangles yet */
  101.     SetPort (log_window);
  102.     log_text = TENew(&temp_rect, &temp_rect);
  103.     
  104.     /* Set the text characteristics */
  105.     (*log_text)->txFont = monaco;        /* Monaco font */
  106.     (*log_text)->txSize = 9;            /* 9 point */
  107.     (*log_text)->lineHeight = 11;        /* 11 points line height */
  108.     (*log_text)->fontAscent = 9;        /* 9 points font ascent */
  109.     
  110.     /* Enable automatic scrolling */
  111.     TEAutoView (TRUE, log_text);
  112.  
  113.     /* Create the scroll bars; don't worry about the rect yet */
  114.     vert_scroll_bar = NewControl (log_window, &temp_rect, "",
  115.                                     TRUE, 0, 0, 32767, scrollBarProc, 0);
  116.     horiz_scroll_bar = NewControl (log_window, &temp_rect, "",
  117.                                     TRUE, 0, 0, 0, scrollBarProc, 0);
  118.  
  119.     /* Disable the horizontal scroll bar (permanently) */
  120.     HiliteControl (horiz_scroll_bar, 255);
  121.  
  122.     /* Set destRect to be as wide as the window, but zero height */
  123.     SetRect (&((*log_text)->destRect), 2, 2, LOG_WINDOW_WIDTH - 20, 2);
  124.  
  125.     /* Set the zoomed size */
  126.     wstate_data = (WStateData *) *( ((WindowPeek) log_window)->dataHandle);
  127.     SetRect (&(wstate_data->stdState), 3, 40, LOG_WINDOW_WIDTH,
  128.                 drag_window_rect.bottom - drag_window_rect.top - 36);
  129.     
  130.     /* This global will tell the db (printf debug message macro in macerrors.h) 
  131.      * that we can send debug messages to the log window and not a console.
  132.      */
  133.     log_window_available = TRUE;
  134.     
  135. }    /* setup_log_window() */
  136.  
  137.  
  138.  
  139. /*****************************************************************************\
  140. * procedure show_log_window                                                   *
  141. *                                                                             *
  142. * Purpose: This procedure displays the log window.                            *
  143. *                                                                             *
  144. *                                                                             *
  145. * Created by: Greg Ferrar                                                     *
  146. * Created on: September 3, 1992                                               *
  147. * Modified:                                                                   *
  148. *   WHO          WHEN             WHAT                                        *
  149. \*****************************************************************************/
  150.  
  151. void show_log_window(Boolean bring_to_front)
  152. {
  153.  
  154.     /* Show the window */
  155.     ShowWindow (log_window);
  156.     
  157.     /* Bring it to the front if we're supposed to */
  158.     SelectWindow (log_window);
  159.     
  160.     /* Set the text to "Hide Log Window" */
  161.     SetItem (windows_menu, SHOW_LOG_ITEM, "\pHide Log Window");
  162.     
  163. }    /* show_log_window() */
  164.  
  165.  
  166.  
  167. /*****************************************************************************\
  168. * procedure hide_log_window                                                   *
  169. *                                                                             *
  170. * Purpose: This procedure hides the log window.                               *
  171. *                                                                             *
  172. *                                                                             *
  173. * Created by: Greg Ferrar                                                     *
  174. * Created on: September 3, 1992                                               *
  175. * Modified:                                                                   *
  176. *   WHO          WHEN             WHAT                                        *
  177. \*****************************************************************************/
  178.  
  179. void hide_log_window(void)
  180. {
  181.  
  182.     /* Hide the window */
  183.     HideWindow (log_window);
  184.     
  185.     /* Set the text of the Windows menu to "Show Log Window" */
  186.     SetItem (windows_menu, SHOW_LOG_ITEM, "\pShow Log Window");
  187.     
  188. }    /* hide_log_window() */
  189.  
  190.  
  191.  
  192. /*****************************************************************************\
  193. * procedure update_log_window                                                 *
  194. *                                                                             *
  195. * Purpose: This procedure updates the log window.                             *
  196. *                                                                             *
  197. * Created by: Greg Ferrar                                                     *
  198. * Created on: August 28, 1992                                                 *
  199. * Modified:                                                                   *
  200. \*****************************************************************************/
  201.  
  202. void update_log_window (void)
  203. {
  204.  
  205.     /* Begin the update */
  206.     BeginUpdate(log_window);
  207.  
  208.     /* Update the log text */
  209.     TEUpdate(&log_text_rect, log_text);
  210.  
  211.     /* Draw the scroll bar */
  212.     DrawControls (log_window);
  213.     
  214.     /* Draw the grow icon */
  215.     DrawGrowIcon (log_window);
  216.  
  217.     /* terminate the update */
  218.     EndUpdate(log_window);
  219.  
  220. }    /* update_log_window() */
  221.  
  222. /*****************************************************************************\
  223. * procedure mac_write                                                         *
  224. *                                                                             *
  225. * Purpose: This procedure is called every time rtrace wants to write to a     *
  226. *          file.  If it is headed for the log file, this intercepts it and    *
  227. *          sends it to the log window too.                                    *
  228. *                                                                             *
  229. * Parameters: file: logfile name (also goes to log window)                    *
  230. *             format string similar to fprintf.                               *
  231. *                                                                             *
  232. * Created by: Reid Judd                                                       *
  233. * Created on: September 18, 1992                                              *
  234. * Modified:                                                                   *
  235. \*****************************************************************************/
  236.  
  237. void mac_write (FILE *file, ...)
  238. {
  239.     va_list arglist;
  240.     char    *format;
  241.     char    string[200];
  242.  
  243.     /* Give background processes some time */
  244.     process_mac_event();
  245.  
  246.     /* Get the argument list */
  247.     va_start(arglist, file);
  248.  
  249.     /* Get the format string */
  250.     format = va_arg(arglist, char *);
  251.  
  252.     /* Generate a string from the arguments */
  253.     vsprintf(string, format, arglist);
  254.     
  255.     /* If this is being output to the log file, put it in the log window */
  256.     if (file == stdout_file)
  257.         {
  258.             
  259.         /* If the last character is a newline, convert it to a into a return */
  260.         if (string[strlen(string) - 1] == '\n')
  261.             string[strlen(string) - 1] = '\r';
  262.         
  263.         /* Add the string to the log window */
  264.         add_line_to_log_window(string);
  265.         
  266.         }
  267.  
  268.     /* Write the string to the file */
  269.     fputs(string, file);
  270.     
  271.     /* Done processing argument lists */
  272.     va_end(arglist);
  273.  
  274. }    /* mac_write() */
  275.  
  276.  
  277.  
  278. /*****************************************************************************\
  279. * procedure add_line_to_log_window                                            *
  280. *                                                                             *
  281. * Purpose: This procedure adds a line of text to the log window, and updates  *
  282. *          it appropriately.                                                  *
  283. *                                                                             *
  284. * Parameters: line: line to insert                                            *
  285. *                                                                             *
  286. * Created by: Greg Ferrar                                                     *
  287. * Created on: August 28, 1992                                                 *
  288. * Modified:                                                                   *
  289. \*****************************************************************************/
  290.  
  291. void add_line_to_log_window (char *line)
  292. {
  293.  
  294.     /* If there are already the maximum number of lines, delete the first */
  295.     if ((*log_text)->nLines == MAX_NUM_LOG_LINES)
  296.         {
  297.         
  298.         /* Select the first line */
  299.         TESetSelect(0, (*log_text)->lineStarts[1], log_text);
  300.         
  301.         /* Delete the first line */
  302.         TEDelete (log_text);
  303.  
  304.         }
  305.  
  306.     /* Move the insertion point to the end */
  307.     TESetSelect(32767, 32767, log_text);
  308.     
  309.     /* Insert the text */
  310.     TEInsert(line, strlen(line), log_text);
  311.  
  312.     /* If this line ends with a return we have a new line in out file.
  313.         Get the new total height of the text in pixels */
  314.     if (line[strlen(line) - 1] == '\r')
  315.         {
  316.         text_height += LINE_HEIGHT;
  317.         (*log_text)->destRect.bottom += LINE_HEIGHT;
  318.  
  319.         /* Set the new maximum control height */
  320.         SetCtlMax(vert_scroll_bar, text_height - window_height);
  321.  
  322.         /* update the scroll bar */
  323.         update_scroll_bar ();
  324.         }
  325.     
  326.     /* Make this line globally available, in case it's an error message */
  327.     strcpy (last_log_line, line);
  328.  
  329. }    /* add_line_to_log_window() */
  330.  
  331.  
  332.  
  333. /*****************************************************************************\
  334. * procedure update_scroll_bar                                                 *
  335. *                                                                             *
  336. * Purpose: This procedure calls update_scroll_bar_with_active, using the      *
  337. *          current log window active state.                                   *
  338. *                                                                             *
  339. * Created by: Greg Ferrar                                                     *
  340. * Created on: August 28, 1992                                                 *
  341. * Modified:                                                                   *
  342. \*****************************************************************************/
  343.  
  344. void update_scroll_bar(void)
  345. {
  346.  
  347.     update_scroll_bar_with_active(((WindowPeek) log_window)->hilited);
  348.  
  349. }    /* update_scroll_bar() */
  350.  
  351.  
  352.  
  353. /*****************************************************************************\
  354. * procedure update_scroll_bar_with_active                                     *
  355. *                                                                             *
  356. * Purpose: This procedure updates the vertical scroll bar, according to the   *
  357. *          log TERec and the setting of active.                               *
  358. *                                                                             *
  359. * Parameters: active: FALSE if the scroll bar should be deactivated           *
  360. *                                                                             *
  361. * Created by: Greg Ferrar                                                     *
  362. * Created on: August 28, 1992                                                 *
  363. * Modified:                                                                   *
  364. \*****************************************************************************/
  365.  
  366. void update_scroll_bar_with_active(Boolean active)
  367. {
  368.  
  369.     /* Set the thumb to the correct place */
  370.     SetCtlValue(vert_scroll_bar, (*log_text)->viewRect.top - (*log_text)->destRect.top);
  371.  
  372.     /* Deactivate the scroll bar if there's no way to scroll, or if the
  373.         window isn't active */
  374.     if ( ( ((*log_text)->destRect.top >= (*log_text)->viewRect.top) &&
  375.             ((*log_text)->destRect.bottom <= (*log_text)->viewRect.bottom) ) ||
  376.                 !active )
  377.         
  378.         HiliteControl(vert_scroll_bar, 255);
  379.     
  380.     /* Otherwise, activate it */
  381.     else
  382.  
  383.         HiliteControl (vert_scroll_bar, 0);
  384.  
  385. }    /* update_scroll_bar_with_active() */
  386.  
  387.  
  388.  
  389. /*****************************************************************************\
  390. * procedure handle_log_click                                                  *
  391. *                                                                             *
  392. * Purpose: This procedure handles a click in the content region of the log    *
  393. *          window.                                                            *
  394. *                                                                             *
  395. * Created by: Greg Ferrar                                                     *
  396. * Created on: August 29, 1992                                                 *
  397. * Modified:                                                                   *
  398. \*****************************************************************************/
  399.  
  400. void handle_log_click(Point where)
  401. {
  402.  
  403.     short             part;            /* part of the control which was hit */
  404.     short             old_value;        /* the old value of the scroll bar */
  405.     short             new_value;        /* the new value of the scroll bar */
  406.     short             scroll_distance;/* the distance to scroll */
  407.     ControlHandle    control;        /* the scroll bar */
  408.  
  409.     /* Find if it was in a scroll bar */
  410.     SetPort (log_window);
  411.     GlobalToLocal (&where);
  412.     part = FindControl(where, log_window, &control);
  413.     
  414.     /* If it was the vertical scroll bar, handle it */
  415.     if (control == vert_scroll_bar)
  416.         {
  417.         switch (part)
  418.             {
  419.             case inUpButton:
  420.             case inDownButton:
  421.             case inPageUp:
  422.             case inPageDown:
  423.                 TrackControl(control, where, scroll_action_proc);
  424.                 
  425.                 break;
  426.             case inThumb:
  427.                 
  428.                 /* Remember what the original value is */
  429.                 old_value = GetCtlValue(control);
  430.                 
  431.                 /* Let user drag the thumb */
  432.                 TrackControl(control, where, NULL);
  433.                 
  434.                 /* Get the new value of the control */
  435.                 new_value = GetCtlValue(control);
  436.                 
  437.                 /* find distance to scroll */
  438.                 scroll_distance = (old_value - new_value) -
  439.                                     (old_value - new_value) % LINE_HEIGHT;
  440.                 
  441.                 /* Scroll the text appropriately */
  442.                 TEPinScroll (0, scroll_distance, log_text);
  443.                 
  444.                 /* Update the scroll bar */
  445.                 update_scroll_bar();
  446.  
  447.             }
  448.         }
  449.  
  450. }    /* handle_log_click() */
  451.  
  452.  
  453. pascal void scroll_action_proc(ControlHandle control, short part)
  454. {
  455.     
  456.     short vscroll;        /* distance to scroll vertically */
  457.  
  458.     switch (part)
  459.         {
  460.         case inUpButton:
  461.             vscroll = LINE_HEIGHT;
  462.             break;
  463.         case inDownButton:
  464.             vscroll = -LINE_HEIGHT;
  465.             break;
  466.         case inPageUp:
  467.             vscroll = ((*log_text)->viewRect.bottom - (*log_text)->viewRect.top);
  468.             break;
  469.         case inPageDown:
  470.             vscroll = -((*log_text)->viewRect.bottom - (*log_text)->viewRect.top);
  471.             break;
  472.         }
  473.  
  474.     TEPinScroll (0, vscroll, log_text);
  475.  
  476.     if ((*log_text)->viewRect.bottom > (*log_text)->destRect.bottom)
  477.  
  478.         /* If the bottom of the text is above the bottom of the window,
  479.             set the scroll bar at its maximum */
  480.         SetCtlValue(control, GetCtlMax(control));
  481.  
  482.     else
  483.             
  484.         /* Otherwise, set it according to the current position in the text */    
  485.         SetCtlValue(control, (*log_text)->viewRect.top - (*log_text)->destRect.top);
  486.  
  487. }    /* scroll_action_proc() */
  488.  
  489.  
  490.  
  491. /*****************************************************************************\
  492. * procedure grow_log_window                                                   *
  493. *                                                                             *
  494. * Purpose: This procedure handles a click in the grow region of the log       *
  495. *          window.                                                            *
  496. *                                                                             *
  497. * Created by: Greg Ferrar                                                     *
  498. * Created on: August 29, 1992                                                 *
  499. * Modified:                                                                   *
  500. \*****************************************************************************/
  501.  
  502. void grow_log_window(Point where)
  503. {
  504.  
  505.     Rect        size_rect = {48, LOG_WINDOW_WIDTH+1, 32767, LOG_WINDOW_WIDTH+1};
  506.                                     /* bounds on size of window */
  507.     long        new_size;            /* requested size */
  508.     short        width, height;        /* requested size as shorts */
  509.     short        real_height;        /* height after pinning */
  510.  
  511.     /* Let user resize the window */
  512.     new_size = GrowWindow(log_window, where, &size_rect);
  513.  
  514.     if (new_size)
  515.         {
  516.         
  517.         /* Get new width and height-- adjust height to an even number of
  518.             lines of text fit */
  519.         width = LoWord(new_size);
  520.         height = HiWord(new_size);
  521.         real_height = height - ((height - 9) % LINE_HEIGHT);
  522.         
  523.         /* Resize the window as requested */
  524.         SizeWindow(log_window, width, real_height, TRUE);
  525.         
  526.         /* Move the resize the text and scroll bars to accomodate */
  527.         log_window_resized();
  528.         
  529.         /* Force the window to completely update */
  530.         SetPort (log_window);
  531.         EraseRect (&log_window->portRect);
  532.         InvalRect (&log_window->portRect);
  533.         
  534.         }
  535. }
  536.  
  537.  
  538.  
  539. /*****************************************************************************\
  540. * procedure handle_log_window_zoom                                            *
  541. *                                                                             *
  542. * Purpose: This procedure handles a click in the zoom region of the log       *
  543. *          window.                                                            *
  544. *                                                                             *
  545. * Created by: Greg Ferrar                                                     *
  546. * Created on: August 29, 1992                                                 *
  547. * Modified:                                                                   *
  548. \*****************************************************************************/
  549.  
  550. void handle_log_window_zoom(Point where, short part_code)
  551. {
  552.  
  553.     /* Track user until (s)he releases the mouse */
  554.     if (TrackBox (log_window, where, part_code))
  555.         {
  556.  
  557.         /* Prepare for zoom */
  558.         SetPort (log_window);
  559.         EraseRect (&log_window->portRect);
  560.         
  561.         /* Zoom */
  562.         ZoomWindow(log_window, part_code, TRUE);
  563.     
  564.         /* change the text and scroll bars to accommodate the new size */
  565.         log_window_resized();
  566.         }    
  567.  
  568. }    /* handle_log_window_zoom() */
  569.  
  570.  
  571.  
  572. /*****************************************************************************\
  573. * procedure log_window_resized                                                *
  574. *                                                                             *
  575. * Purpose: This procedure sets the size of the log text box and the scroll    *
  576. *          bars according the the size of the log window.                     *
  577. *                                                                             *
  578. * Created by: Greg Ferrar                                                     *
  579. * Created on: August 29, 1992                                                 *
  580. * Modified:                                                                   *
  581. \*****************************************************************************/
  582.  
  583. void    log_window_resized(void)
  584. {
  585.  
  586.     /* Copy the window rectangle into the text rectangle */
  587.     BlockMove (&(log_window->portRect), &log_text_rect, 8);
  588.     
  589.     /* Move it to the origin */
  590.     OffsetRect (&log_text_rect, -log_text_rect.left, -log_text_rect.top);
  591.     
  592.     /* Shrink the text rectangle to make room for the scroll bars */
  593.     log_text_rect.right -= 16;
  594.     log_text_rect.bottom -= 16;
  595.     
  596.     /* Inset the text rect to make a 2-pixel margin */
  597.     InsetRect (&log_text_rect, 2, 2);
  598.     
  599.     /* Resize the text to fit its rectangle */
  600.     BlockMove (&log_text_rect, &((*log_text)->viewRect), 8);
  601.  
  602.     /* Move the vertical scroll bar to the right of the text rectangle */
  603.     MoveControl (vert_scroll_bar, log_text_rect.right + 3, -1);
  604.     
  605.     /* Resize the vertical scroll bar to fill the window vertically */
  606.     SizeControl (vert_scroll_bar, 16, log_text_rect.bottom + 5);
  607.  
  608.     /* Move the horizontal scroll bar to right below text rectangle */
  609.     MoveControl (horiz_scroll_bar, -1, log_text_rect.bottom + 3);
  610.     
  611.     /* Resize the horizontal scroll bar to fill the window horizontally */
  612.     SizeControl (horiz_scroll_bar, log_text_rect.right + 5, 16);
  613.  
  614.     /* Recompute window height */
  615.     window_height = log_text_rect.bottom - log_text_rect.top;
  616.  
  617.     /* Redraw the scroll bar */
  618.     update_scroll_bar();
  619.  
  620.     /* Set the new maximum control height */
  621.     SetCtlMax(vert_scroll_bar, text_height - window_height);
  622.  
  623. }    /* log_window_resized() */
  624.  
  625.